package com.xbongbong.saas.model.impl;

import com.alibaba.fastjson.JSONObject;
import com.xbongbong.paas.constant.PaasConstant;
import com.xbongbong.paas.domain.dao.PaasFormDataDao;
import com.xbongbong.paas.domain.entity.OneFormNumEntity;
import com.xbongbong.paas.domain.entity.PaasFormDataEntity;
import com.xbongbong.paas.domain.entity.PaasFormSubDataEntity;
import com.xbongbong.paas.domain.entity.ext.PaasFormDataEntityExt;
import com.xbongbong.paas.elasticsearch.model.PaasEsModel;
import com.xbongbong.paas.elasticsearch.model.PaasFormDataEsModel;
import com.xbongbong.paas.elasticsearch.pojo.dto.InsertDTO;
import com.xbongbong.paas.enums.DelEnum;
import com.xbongbong.paas.enums.FieldTypeEnum;
import com.xbongbong.paas.enums.IndexTypeEnum;
import com.xbongbong.paas.model.PaasFormPaasSubDataModel;
import com.xbongbong.paas.pojo.dto.UpdateByQueryDTO;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.paas.toolbox.util.CollectionsUtil;
import com.xbongbong.paas.toolbox.util.DateTimeUtil;
import com.xbongbong.paas.toolbox.util.DateUtil;
import com.xbongbong.paas.toolbox.wrap.EnableApiCallBack;
import com.xbongbong.paas.util.DataUtil;
import com.xbongbong.pro.domain.entity.UpdateDataEntity;
import com.xbongbong.pro.domain.entity.UpdateDataValueEntity;
import com.xbongbong.pro.enums.ApiCallBackEnum;
import com.xbongbong.pro.enums.SaasMarkEnum;
import com.xbongbong.pro.formdata.pojo.PaasFormDataNoDataPojo;
import com.xbongbong.saas.constant.ParameterConstant;
import com.xbongbong.saas.constant.StringConstant;
import com.xbongbong.saas.enums.OperateTypeEnum;
import com.xbongbong.saas.enums.RedundantTemplateTypeEnum;
import com.xbongbong.saas.enums.business.BomBillEnum;
import com.xbongbong.saas.enums.business.CommunicatePlanEnum;
import com.xbongbong.saas.enums.business.ContactEnum;
import com.xbongbong.saas.enums.business.ContractEnum;
import com.xbongbong.saas.enums.business.CustomerManagementEnum;
import com.xbongbong.saas.enums.business.InventoryEnum;
import com.xbongbong.saas.enums.business.InvoiceEnum;
import com.xbongbong.saas.enums.business.PayPlanEnum;
import com.xbongbong.saas.enums.business.PaySheetEnum;
import com.xbongbong.saas.enums.business.PaymentEnum;
import com.xbongbong.saas.enums.business.PaymentSheetEnum;
import com.xbongbong.saas.enums.business.PaymentTaskEnum;
import com.xbongbong.saas.enums.business.ProductionOrderEnum;
import com.xbongbong.saas.enums.business.PurchaseEnum;
import com.xbongbong.saas.enums.business.QuotationEnum;
import com.xbongbong.saas.enums.business.RefundEnum;
import com.xbongbong.saas.enums.business.ReturnedPurchaseEnum;
import com.xbongbong.saas.enums.business.SalesOpportunityEnum;
import com.xbongbong.saas.enums.business.SupplierContactEnum;
import com.xbongbong.saas.enums.business.SupplierEnum;
import com.xbongbong.saas.enums.business.TransferEnum;
import com.xbongbong.saas.enums.business.WarehouseEnum;
import com.xbongbong.saas.enums.business.WorkOrderEnum;
import com.xbongbong.saas.model.PaasFormDataModel;
import com.xbongbong.saas.model.PaasFormSubDataModel;
import com.xbongbong.saas.util.StandardizeDataUtil;
import org.elasticsearch.action.support.WriteRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ExecutionException;

/**
 * @author: wufeng
 * @date: 2018/8/13 15:22
 * @desrcption: PaaS流程任务实现类
 */
@Service("paasFormDataModel")
public class PaasFormDataModelImpl implements PaasFormDataModel {

    private static final String COLUMNS = " id, corpid, app_id, menu_id, form_id, serial_no,owner_id,department_id, flow_status, data, creator_id, add_time, update_time, del ";
    private static final Logger LOG = LoggerFactory.getLogger(PaasFormDataModelImpl.class);

    @Resource
    private PaasFormDataDao paasFormDataDao;
    @Resource
    private PaasFormDataEsModel paasFormDataEsModel;
    @Resource
    private PaasFormPaasSubDataModel paasFormPaasSubDataModel;
    @Resource
    private PaasFormSubDataModel paasFormSubDataModel;
    @Resource
    private PaasEsModel paasEsModel;

    @Override
    @EnableApiCallBack(callBackBusiness = ApiCallBackEnum.SYSTEM, saasMark = SaasMarkEnum.PAAS, operateTypeEnum = OperateTypeEnum.NEW)
    public Integer insert(PaasFormDataEntity entity) throws XbbException {
        long now = DateUtil.getInt();
        entity.setAddTime(now);
        entity.setUpdateTime(now);

        paasFormSubDataModel.transferSubForm(entity, IndexTypeEnum.IDX_SUB_FORM_DATA);
        StandardizeDataUtil.standardizeNotString(entity);

        Integer insert = paasFormDataDao.insert(entity);
        //ES数据插入
        paasFormDataEsModel.insert(entity);

        paasFormSubDataModel.insertSubFormData(entity, IndexTypeEnum.IDX_SUB_FORM_DATA);

        return insert;
    }

    @Override
    @EnableApiCallBack(callBackBusiness = ApiCallBackEnum.SYSTEM, saasMark = SaasMarkEnum.PAAS, operateTypeEnum = OperateTypeEnum.NEW)
    public Integer insert(PaasFormDataEntity entity, WriteRequest.RefreshPolicy refreshPolicy) throws XbbException {
        long now = DateUtil.getInt();
        entity.setAddTime(now);
        entity.setUpdateTime(now);

        paasFormSubDataModel.transferSubForm(entity, IndexTypeEnum.IDX_SUB_FORM_DATA);
        StandardizeDataUtil.standardizeNotString(entity);

        Integer insert = paasFormDataDao.insert(entity);
        //ES数据插入
        paasFormDataEsModel.insert(entity, refreshPolicy);

        paasFormSubDataModel.insertSubFormData(entity, IndexTypeEnum.IDX_SUB_FORM_DATA);

        return insert;
    }

    @Override
    @EnableApiCallBack(callBackBusiness = ApiCallBackEnum.SYSTEM, saasMark = SaasMarkEnum.PAAS, operateTypeEnum = OperateTypeEnum.NEW, isBatch = true)
    public void insertBatch(List<PaasFormDataEntity> paasFormDataList) throws XbbException {

        for (PaasFormDataEntity paasFormDataEntity : paasFormDataList) {
            paasFormSubDataModel.transferSubForm(paasFormDataEntity, IndexTypeEnum.IDX_SUB_FORM_DATA);
        }
        StandardizeDataUtil.standardize4EntityList(paasFormDataList);

        paasFormDataDao.insertBatch(paasFormDataList);
        //ES数据插入
        paasFormDataEsModel.insertBatch(paasFormDataList);

        paasFormSubDataModel.insertBatchSubFormData(paasFormDataList, IndexTypeEnum.IDX_SUB_FORM_DATA);
    }


    @Override
    public List<PaasFormDataEntityExt> findEntitys(Map<String, Object> map) {
        if (!map.containsKey(StringConstant.COLUMNS)) {
            map.put("columns", new StringBuffer(COLUMNS));
        }
//        return paasFormDataDao.findEntitys(map);

        List<PaasFormDataEntityExt> entitys = paasFormDataDao.findEntitys(map);

        Object corpid = map.get(ParameterConstant.CORPID);
        if (Objects.nonNull(corpid)) {
            paasFormSubDataModel.findSubEntity(corpid.toString(), entitys, IndexTypeEnum.IDX_SUB_FORM_DATA);
        }
        return entitys;

    }

    /**
     * 只拉去原始数据
     * @param map
     * @return
     */
    @Override
    public List<PaasFormDataEntityExt> findEntityOriginal(Map<String, Object> map) {
        return paasFormDataDao.findEntityOriginal(map);
    }

    @Override
    public PaasFormDataEntityExt getByKey(Long key, String corpid) {
//        return paasFormDataDao.getByKey(key, corpid);
        PaasFormDataEntityExt paasFormDataEntityExt = paasFormDataDao.getByKey(key, corpid);

        paasFormSubDataModel.findSubEntity(corpid, Collections.singletonList(paasFormDataEntityExt), IndexTypeEnum.IDX_SUB_FORM_DATA);
//        List<PaasFormSubDataEntity> paasFormPaasSubDataEntities = paasFormPaasSubDataModel.getByDataId(key, corpid);
//        Map<String, JSONArray> subMap = new HashMap<>();
//        paasFormPaasSubDataEntities.forEach(item -> {
//            JSONObject data = item.getData();
//            data.put(BusinessConstant.SUB_DATA_ID, item.getId());
//            item.setData(data);
//            subMap.computeIfAbsent(item.getAttr(), v-> new JSONArray()).add(item.getData());
//        });
//
//        JSONObject data = paasFormDataEntityExt.getData();
//        subMap.forEach(data::put);
//        paasFormDataEntityExt.setData(data);
        return paasFormDataEntityExt;
    }

    @Override
    public Integer getEntitysCount(Map<String, Object> map) {
        return paasFormDataDao.getEntitysCount(map);
    }

    @Override
    public List<PaasFormDataEntityExt> findEntitysWithoutSub(Map<String, Object> param) {
        return paasFormDataDao.findEntitys(param);
    }

    @Override
    @EnableApiCallBack(callBackBusiness = ApiCallBackEnum.SYSTEM, saasMark = SaasMarkEnum.PAAS, operateTypeEnum = OperateTypeEnum.DELETE)
    public Integer delete(Integer key, String corpid) throws ExecutionException, InterruptedException, IOException, XbbException {
        Integer delete = paasFormDataDao.deleteByKey(key, corpid);
        //ES数据更新del=1
        paasFormDataEsModel.delete(Long.valueOf(key), corpid);
        // 主表删除，子表单del置为4
        paasFormSubDataModel.deleteByDataId(Long.valueOf(key), corpid, IndexTypeEnum.IDX_SUB_FORM_DATA);
        return delete;
    }

    @Override
    @EnableApiCallBack(callBackBusiness = ApiCallBackEnum.SYSTEM, saasMark = SaasMarkEnum.PAAS, operateTypeEnum = OperateTypeEnum.EDIT)
    public Integer update(PaasFormDataEntity entity) throws XbbException {
        long now = DateUtil.getInt();
        entity.setUpdateTime(now);

        paasFormSubDataModel.transferSubForm(entity, IndexTypeEnum.IDX_SUB_FORM_DATA);
        StandardizeDataUtil.standardizeNotString(entity);
        Integer update = paasFormDataDao.update(entity);
        Integer updateSub = paasFormSubDataModel.updateSubFormData(entity, IndexTypeEnum.IDX_SUB_FORM_DATA);
        //ES的更新
        if (Objects.equals(1, update) || Objects.equals(1, updateSub)) {
            update = paasFormDataDao.updateTime(now + 1, entity.getId(), entity.getCorpid());
            paasFormDataEsModel.update(entity);
        }
        if (Objects.nonNull(entity.getSubFormData()) && !entity.getSubFormData().isEmpty()) {
            entity.getData().putAll(entity.getSubFormData());
        }
        return update;
    }

    @Override
    @EnableApiCallBack(callBackBusiness = ApiCallBackEnum.SYSTEM, saasMark = SaasMarkEnum.PAAS, operateTypeEnum = OperateTypeEnum.DELETE, isBatch = true)
    public Integer deleteBatch(List<Long> list, String corpid, Integer del) throws XbbException {

        Integer integer = paasFormDataDao.deleteBatch(list, corpid, del);
//        主表删除，子表单不删除，不然还原的时候，子表数据不知道还原哪些
//        paasFormPaasSubDataModel.deleteBatchByDataId(list, corpid);
        //ES根据id批量设置del=1
        updateBatchDel(list, corpid, del);

        paasFormSubDataModel.deleteBatchByDataId(list, corpid, IndexTypeEnum.IDX_SUB_FORM_DATA, DelEnum.DELETE_SUBFORM);

        return integer;
    }

    @Override
    @EnableApiCallBack(callBackBusiness = ApiCallBackEnum.SYSTEM, saasMark = SaasMarkEnum.PAAS, operateTypeEnum = OperateTypeEnum.EDIT, isBatch = true)
    public Integer updateBatch(List<UpdateDataEntity> list, String corpid) throws XbbException {
        //1. 先拿到子表单数据
        List<UpdateDataEntity> subList = DataUtil.getUpdateSubDataList(list);
        // 2. 主表删掉子表单数据
        DataUtil.removeSubDataInData(list);
        StandardizeDataUtil.standardizeList(list);
        Integer integer = paasFormDataDao.updateBatch(list, corpid);
        paasFormDataEsModel.updateBatch(list);
        if (!subList.isEmpty()) {
            paasFormPaasSubDataModel.updateBatch(subList, corpid);
        }
        return integer;
    }

    @Override
    @EnableApiCallBack(callBackBusiness = ApiCallBackEnum.SYSTEM, saasMark = SaasMarkEnum.PAAS, operateTypeEnum = OperateTypeEnum.EDIT, isBatch = true)
    public Integer updateBatch(List<UpdateDataEntity> list, String corpid, WriteRequest.RefreshPolicy refreshPolicy) throws XbbException {
        //1. 先拿到子表单数据
        List<UpdateDataEntity> subList = DataUtil.getUpdateSubDataList(list);
        // 2. 主表删掉子表单数据
        DataUtil.removeSubDataInData(list);
        Integer integer = 0;
        if (CollectionsUtil.isNotEmpty(list)) {
            StandardizeDataUtil.standardizeList(list);
            integer = paasFormDataDao.updateBatch(list, corpid);
            paasFormDataEsModel.updateBatch(list, refreshPolicy);
        }
        if (!subList.isEmpty()) {
            List<PaasFormSubDataEntity> insertList = new ArrayList<>();
            Iterator<UpdateDataEntity> iterator = subList.iterator();
            while (iterator.hasNext()) {
                UpdateDataEntity v = iterator.next();
                if (Objects.isNull(v.getId())) {
                    JSONObject data = new JSONObject();
                    List<UpdateDataValueEntity> dataList = v.getData();
                    dataList.forEach(item -> {
                        data.put(item.getKey().replace("$.", ""), item.getValue());
                    });
                    PaasFormSubDataEntity paasFormSubDataEntity = new PaasFormSubDataEntity(v.getFormId(), corpid, v.getParentId(), v.getAttr(), data);
                    insertList.add(paasFormSubDataEntity);
                    iterator.remove();
                }
            }
            if (!insertList.isEmpty()) {
                paasFormPaasSubDataModel.insertBatch(insertList);
            }
            paasFormPaasSubDataModel.updateBatch(subList, corpid);
        }
        return integer;
    }

    @Override
    public Integer fastUpdate(Map<String, Object> param, Long key, String corpid) throws XbbException{
        // TODO: 2020/9/11 子表单没有快速编辑
        StandardizeDataUtil.standardizeMap(param);
        Integer  integer = paasFormDataDao.fastUpdate(param, key, corpid);
        String attr = param.get("attr").toString();
        Object value = param.get("value");
        UpdateByQueryDTO updateByQueryDTO = new UpdateByQueryDTO();
        List<Long> idsList = new ArrayList<>();
        idsList.add(key);
        updateByQueryDTO.setIdList(idsList);
        updateByQueryDTO.setCorpid(corpid);
        Map<String, Object> updateDataMap = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        updateDataMap.put("data."+attr, value);
        updateByQueryDTO.setUpdateDataMap(updateDataMap);
//        paasFormDataEsModel.updateByIdIn(updateByQueryDTO);
        return integer;
    }

    @Override
    public List<PaasFormDataEntity> findEntitysByIds(List<Long> formDataId, String corpid, Integer del) {
//        return paasFormDataDao.findEntitysByIds(formDataId, corpid, del);
        List<PaasFormDataEntity> paasFormDataList = paasFormDataDao.findEntitysByIds(formDataId, corpid, del);

        paasFormSubDataModel.findSubEntity(corpid, paasFormDataList, IndexTypeEnum.IDX_SUB_FORM_DATA);
        return paasFormDataList;
    }

    @Override
    public Integer restoreBatch(List<Long> formDataIds, String corpid, Integer del) throws XbbException {
        Integer count = paasFormDataDao.restoreBatch(formDataIds, corpid, del);
        updateBatchDel(formDataIds, corpid, del);

        paasFormSubDataModel.restoreBatch(formDataIds, corpid, IndexTypeEnum.IDX_SUB_FORM_DATA);
        return count;
    }

    @Override
    public Integer thoroughDeleteBatch(List<Long> formDataIds, String corpid, Integer del) throws XbbException {
        Integer count = paasFormDataDao.thoroughDeleteBatch(formDataIds, corpid, del);
        updateBatchDel(formDataIds, corpid, del);
        List<? extends PaasFormSubDataEntity> entities = paasFormSubDataModel.getByDataIdList(formDataIds, DelEnum.DELETE_SUBFORM.getDel(), corpid, IndexTypeEnum.IDX_SUB_FORM_DATA);
        paasFormPaasSubDataModel.updateDel((List<PaasFormSubDataEntity>)  entities,corpid,  WriteRequest.RefreshPolicy.NONE, DelEnum.getByDel(del));
        return count;
    }

    private void updateBatchDel(List<Long> formDataIds, String corpid, Integer del) throws XbbException {
        Map<String, Object> map = new HashMap<>(PaasConstant.DEFAULT_INITIAL_CAPACITY);
        map.put("del", del);
        if(CollectionsUtil.isNotEmpty(formDataIds)){
/*            if(formDataIds.size() == 1){
                try {
                    paasFormDataEsModel.delete(formDataIds.get(0),corpid);
                } catch (ExecutionException | InterruptedException e) {
                    LOG.error(BuinessDefaultErrorCodeEnum.API_ERROR_200019.getMsg(),e);
                    throw new XbbException(BuinessDefaultErrorCodeEnum.API_ERROR_200019);
                }
            }else{
            }*/
            paasFormDataEsModel.updateBatch(formDataIds, corpid, map);
        }
    }

    @Override
    public OneFormNumEntity getOneFormMaxNum(String corpid) {
        return paasFormDataDao.getOneFormMaxNum(corpid);
    }

    @Override
    @EnableApiCallBack(callBackBusiness = ApiCallBackEnum.SYSTEM, saasMark = SaasMarkEnum.PAAS, operateTypeEnum = OperateTypeEnum.EDIT, isBatch = true)
    public Integer batchUpdateOwner(List<Long> dataIdList, String corpid, String userId, WriteRequest.RefreshPolicy refreshPolicy) throws XbbException {
        Integer integer = paasFormDataDao.batchUpdateOwner(dataIdList, corpid, userId);
        Map<String, Object> map = new HashMap<>();
        map.put(FieldTypeEnum.OWNERID.getAlias(), userId);
        paasFormDataEsModel.updateBatch(dataIdList, corpid, map);
        return integer;
    }


    /**
     * 获取业务类型主键字段(用于关联列表回显)
     *
     * @param businessType 业务类型
     * @author long.rao
     * @date 2019-02-26 21:50
     */
    @Override
    public String getFormEntityMainAttr(Integer businessType) {
        RedundantTemplateTypeEnum redundantTemplateTypeEnum = RedundantTemplateTypeEnum.getByCode(businessType);
        String mainAttr = "";
        switch (redundantTemplateTypeEnum) {
            case CUSTOMER:
                mainAttr = CustomerManagementEnum.NAME.getAttr();
                break;
            case CONTRACT:
                mainAttr = ContractEnum.CONTRACT_NO.getAttr();
                break;
            case CONTACT:
                mainAttr = ContactEnum.NAME.getAttr();
                break;
            case SALES_OPPORTUNITY:
                mainAttr = SalesOpportunityEnum.SERIAL_NO.getAttr();
                break;
            case BOMBILL:
                mainAttr = BomBillEnum.SHEET_NO.getAttr();
                break;
            case COMMUNICATE_PLAN:
                mainAttr = CommunicatePlanEnum.NAME.getAttr();
                break;
            case SUPPLIER:
                mainAttr = SupplierEnum.SUPPLIER_NAME.getAttr();
                break;
            case SUPPLIER_CONTACT:
                mainAttr = SupplierContactEnum.NAME.getAttr();
                break;
            case PURCHASE:
                mainAttr = PurchaseEnum.SHEET_NO.getAttr();
                break;
            case PAYMENT:
                mainAttr = PaymentEnum.PAYMENT_NO.getAttr();
                break;
            case WAREHOUSE:
                mainAttr = WarehouseEnum.WAREHOUSE_NAME.getAttr();
                break;
            case INVENTORY:
                mainAttr = InventoryEnum.SHEET_NO.getAttr();
                break;
            case TRANSFER:
                mainAttr = TransferEnum.SHEET_NO.getAttr();
                break;
            case PRODUCTIONORDER:
                mainAttr = ProductionOrderEnum.SHEET_NO.getAttr();
                break;
            case RETURNED_PURCHASE:
                mainAttr = ReturnedPurchaseEnum.SHEET_NO.getAttr();
                break;
            case PAYMENT_SHEET:
                mainAttr = PaymentSheetEnum.SHEET_NO.getAttr();
                break;
            case PAY_SHEET:
                mainAttr = PaySheetEnum.PAY_PLAN_NO.getAttr();
                break;
            case PAY_PLAN:
                mainAttr = PayPlanEnum.PAY_PLAN_NO.getAttr();
                break;
            case INVOICE:
                mainAttr = InvoiceEnum.SHEET_NO.getAttr();
                break;
            case REFUND:
                mainAttr = RefundEnum.REFUND_NO.getAttr();
                break;
            case WORKORDER:
                mainAttr = WorkOrderEnum.SHEET_NO.getAttr();
                break;
            case QUOTATION:
                mainAttr = QuotationEnum.QUOTATION_NO.getAttr();
                break;
            case PAYMENT_TASK:
                mainAttr = PaymentTaskEnum.PAYMENT_TASK_NO.getAttr();
                break;
            default:
                mainAttr = CustomerManagementEnum.NAME.getAttr();
                break;
        }
        return mainAttr;
    }

    /**
     * 查询出最大id，主要用于刷脚本使用
     *
     * @param param
     * @return
     */
    @Override
    public Long getMaxId(Map<String, Object> param) {
        return paasFormDataDao.getMaxId(param);
    }

    /**
     * 更新paas表单更新时间
     *
     * @param id
     * @param corpid
     */
    @Override
    public void updateTime(Long id, String corpid) throws XbbException{
        Long updateTime = DateTimeUtil.getInt();
        paasFormDataDao.updateTime(updateTime,id, corpid);
        InsertDTO insertDTO = new InsertDTO();
        insertDTO.setEsId(corpid+"_"+id);
        Map<String, Object> map = new HashMap<>();
        map.put(FieldTypeEnum.UPDATETIME.getAlias(), updateTime);
        insertDTO.setSource(map);
        insertDTO.setIndexTypeEnum(IndexTypeEnum.IDX_FORM_DATA);
        paasEsModel.update(insertDTO);
    }

    /**
     * 获取paas表单数据，只查询一部分自己需要的数据
     *
     * @param param
     * @return
     */
    @Override
    public List<PaasFormDataNoDataPojo> getPaasFormDataNoDataPojo(Map<String, Object> param) throws XbbException{
        List<PaasFormDataNoDataPojo> paasFormDataNoDataPojos = paasFormDataDao.getPaasFormDataNoData(param);
        return paasFormDataNoDataPojos;
    }
}
